home *** CD-ROM | disk | FTP | other *** search
- /* Packet tracing - top level and generic routines, including hex/ascii
- * Copyright 1991 Phil Karn, KA9Q
- *
- * Mods by G1EMM
- *
- * Tracing to session taken from WNOS3, by Johan. K. Reinalda, WG7J
- */
- #include "global.h"
- #include "ctype.h"
- #include "commands.h"
- #ifndef MSDOS
- #include <time.h>
- #endif
- #include <stdarg.h>
- #include "mbuf.h"
- #include "iface.h"
- #include "pktdrvr.h"
- #include "session.h"
- #include "trace.h"
- #include "usock.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: trace.c,v 1.23 1997/09/07 21:18:28 root Exp root $";
- #endif
-
- /* this variable and the patch to traceprintf assumes that no kwaits
- will be placed in any of the files used for tracing. */
-
- int tracesock;
-
-
- #ifdef TRACE
- static void ascii_dump (FILE * fp, struct mbuf ** bpp);
- static void ctohex (char *buf, int16 c);
- static void fmtline (FILE * fp, int16 addr, char *buf, int16 len);
- static void hex_dump (FILE * fp, struct mbuf ** bpp, int iftype);
- static void showtrace (struct iface * ifp);
- static void plain_dump (FILE * fp, register struct mbuf ** bpp);
-
- extern int Tracesession;
- extern struct session *Trace;
-
- #include "slip.h"
-
- #ifdef MONITOR
- static const char *kissname (struct iface * ifp, struct mbuf * bp, unsigned type);
-
-
- static const char *
- kissname (struct iface *ifp, struct mbuf *bp, unsigned type)
- {
- int port;
-
- if (ifp->type != CL_AX25 || type != CL_KISS)
- return ifp->name;
- port = (bp->data[0] & 0xF0) >> 4;
- if (Slip[ifp->xdev].kiss[port] == NULLIF)
- return ifp->name;
- return Slip[ifp->xdev].kiss[port]->name;
- }
-
- #endif
-
-
- int
- dostrace (int argc, char *argv[], void *p OPTIONAL)
- {
- if (Trace == NULLSESSION) {
- if (argc > 1)
- tputs ("Session tracing not available!\007\n");
- argc = 0; /* No session setup, so don't allow turning it on ! */
- }
- return setbool (&Tracesession, "Trace to session", argc, argv);
- }
-
-
- /* Redefined here so that programs calling dump in the library won't pull
- * in the rest of the package
- */
-
- static char nospace[] = "No space!!\n";
-
- static struct tracecmd Tracecmd[] =
- {
- { "input", IF_TRACE_IN, IF_TRACE_IN },
- { "-input", 0, IF_TRACE_IN },
- { "output", IF_TRACE_OUT, IF_TRACE_OUT },
- { "-output", 0, IF_TRACE_OUT },
- { "broadcast", 0, IF_TRACE_NOBC },
- { "-broadcast", IF_TRACE_NOBC, IF_TRACE_NOBC },
- { "raw", IF_TRACE_RAW, IF_TRACE_RAW },
- { "-raw", 0, IF_TRACE_RAW },
- { "ascii", IF_TRACE_ASCII, IF_TRACE_ASCII | IF_TRACE_HEX },
- { "-ascii", 0, IF_TRACE_ASCII | IF_TRACE_HEX },
- { "hex", IF_TRACE_HEX, IF_TRACE_ASCII | IF_TRACE_HEX },
- { "-hex", IF_TRACE_ASCII, IF_TRACE_ASCII | IF_TRACE_HEX },
- #ifdef MONITOR
- /* borrow a meaningless combination for the new trace type */
- #define IF_TRACE_PLAIN (IF_TRACE_ASCII|IF_TRACE_HEX)
- { "monitor", IF_TRACE_PLAIN, IF_TRACE_ASCII | IF_TRACE_HEX },
- { "-monitor", IF_TRACE_ASCII, IF_TRACE_ASCII | IF_TRACE_HEX },
- #endif
- { "off", 0, 0xffff },
- { NULLCHAR, 0, 0 }
- };
-
-
-
- void
- dump (register struct iface *ifp, int direction, unsigned type, struct mbuf *bp)
- {
- struct mbuf *tbp;
- void (*func) (FILE *, struct mbuf **, int);
- int16 size;
- time_t timer;
- char *cp;
-
- #ifdef KISS /* Let's straighten out this multiport tracing - K5JB */
- if (type == CL_KISS) { /* I don't think we will see CL_AX25 */
- int port; /* don't need this but it improves readability */
- struct iface *kifp;
-
- port = (bp->data[0] & 0xF0) >> 4;
- if ((kifp = Slip[ifp->xdev].kiss[port]) != NULLIF)
- ifp = kifp;
- }
- #endif
-
- if (ifp == NULL || (ifp->trace & direction) == 0)
- return; /* Nothing to trace */
-
- #ifdef UNIX
- /* need to check if the traced-to session is a "blocking" session */
- if (ifp->trsock != -1 && sm_blocked (Tracesession ? Trace : Command))
- return;
- #else
- if (Tracesession) {
- /* Disable trace if this is not Trace-sessions,
- * or when shelled out, and not tracing to file */
- if ((Current != Trace) && (ifp->trfp == stdout))
- return; /* Nothing to trace */
- } else {
- /* Disable trace on non-command sessions or when shelled out */
- if ((Current != Command) && (ifp->trfp == stdout))
- return; /* Nothing to trace */
- }
- #endif
-
- if (ifp->trsock != -1)
- tracesock = ifp->trsock;
- else if (Tracesession)
- tracesock = Trace->output;
- else
- tracesock = Command->output;
-
- (void) time (&timer);
- cp = ctime (&timer);
- cp[24] = '\0';
-
- switch (direction) {
- case IF_TRACE_IN:
- if ((ifp->trace & IF_TRACE_NOBC)
- && (Tracef[type].addrtest != NULLFP ((struct iface *, struct mbuf *)))
- && (*Tracef[type].addrtest) (ifp, bp) == 0)
- return; /* broadcasts are suppressed */
- #ifdef MONITOR
- if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
- traceprintf (ifp->trfp, "(%s) ", kissname (ifp, bp, type));
- else
- #endif
- traceprintf (ifp->trfp, "\n%s - %s recv:\n", cp, ifp->name);
- break;
- case IF_TRACE_OUT:
- #ifdef MONITOR
- if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
- traceprintf (ifp->trfp, "(%s) ", kissname (ifp, bp, type));
- else
- #endif
- traceprintf (ifp->trfp, "\n%s - %s sent:\n", cp, ifp->name);
- break;
- default:
- break;
- }
- if (bp == NULLBUF || (size = len_p (bp)) == 0) {
- traceprintf (ifp->trfp, "empty packet!!\n");
- return;
- }
- if (type < NCLASS)
- func = Tracef[type].tracef;
- else
- func = NULLVFP ((FILE *, struct mbuf **, int));
-
- (void) dup_p (&tbp, bp, 0, size);
- if (tbp == NULLBUF) {
- traceprintf (ifp->trfp, nospace);
- return;
- }
- if (func != NULLVFP ((FILE *, struct mbuf **, int)))
- (*func) (ifp->trfp, &tbp, 1);
- #ifdef MONITOR
- if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
- plain_dump (ifp->trfp, &tbp);
- else
- #endif
- if (ifp->trace & IF_TRACE_ASCII) {
- /* Dump only data portion of packet in ascii */
- ascii_dump (ifp->trfp, &tbp);
- } else if (ifp->trace & IF_TRACE_HEX) {
- /* Dump entire packet in hex/ascii */
- free_p (tbp);
- (void) dup_p (&tbp, bp, 0, len_p (bp));
- if (tbp != NULLBUF)
- hex_dump (ifp->trfp, &tbp, ifp->type);
- else
- traceprintf (ifp->trfp, nospace);
- }
- free_p (tbp);
- }
-
-
- /* Dump packet bytes, no interpretation */
- void
- raw_dump (struct iface *ifp, int direction, struct mbuf *bp)
- {
- struct mbuf *tbp;
-
- /* Dump entire packet in hex/ascii */
- traceprintf (ifp->trfp, "\n******* raw packet dump (%s %s)\n",
- ((direction & IF_TRACE_OUT) ? "send" : "recv"), ifp->name);
- (void) dup_p (&tbp, bp, 0, len_p (bp));
- if (tbp != NULLBUF)
- hex_dump (ifp->trfp, &tbp, ifp->type);
- else
- traceprintf (ifp->trfp, nospace);
- traceprintf (ifp->trfp, "*******\n");
- free_p (tbp);
- return;
- }
-
-
- /* Dump an mbuf in hex */
- static void
- hex_dump (FILE * fp, register struct mbuf **bpp, int iftype)
- {
- int16 n;
- int16 address;
- char buf[16];
-
- if (bpp == NULLBUFP || *bpp == NULLBUF)
- return;
-
- address = 0;
- if (iftype == CL_AX25)
- (void) pullup (bpp, (unsigned char *) buf, 1); /* remove first zero byte */
- while ((n = pullup (bpp, (unsigned char *) buf, sizeof (buf))) != 0) {
- fmtline (fp, address, buf, n);
- address += n;
- }
- }
-
-
- /* Dump an mbuf in ascii */
- static void
- ascii_dump (FILE * fp, register struct mbuf **bpp)
- {
- int c;
- register int16 tot;
-
- if (bpp == NULLBUFP || *bpp == NULLBUF)
- return;
-
- tot = 0;
- while ((c = PULLCHAR (bpp)) != -1) {
- if ((tot % 64) == 0)
- traceprintf (fp, "%04x ", tot);
- traceprintf (fp, "%c", isprint (uchar (c)) ? c : '.');
- if ((++tot % 64) == 0)
- traceprintf (fp, "\n");
- }
- if ((tot % 64) != 0)
- traceprintf (fp, "\n");
- }
-
-
- /* Print a buffer up to 16 bytes long in formatted hex with ascii
- * translation, e.g.,
- * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?
- */
- static void
- fmtline (FILE * fp, int16 addr, char *buf, int16 len)
- {
- char line[100];
- register char *aptr, *cptr;
- register char c;
-
- memset (line, ' ', sizeof (line));
- ctohex (line, (int16) hibyte (addr));
- ctohex (line + 2, (int16) lobyte (addr));
- aptr = &line[6];
- cptr = &line[55];
- while (len-- != 0) {
- c = *buf++;
- ctohex (aptr, (int16) uchar (c));
- aptr += 3;
- c &= 0x7f;
- *cptr++ = isprint (uchar (c)) ? c : '.';
- }
- *cptr++ = '\n';
- *cptr = 0;
- traceprintf (fp, "%s", line);
- }
-
-
- /* Convert byte to two ascii-hex characters */
- static void
- ctohex (register char *buf, register int16 c)
- {
- static char hex[] = "0123456789abcdef";
-
- *buf++ = hex[hinibble (c)];
- *buf = hex[lonibble (c)];
- }
-
-
- #ifdef MONITOR
- /* Dump an mbuf in ascii with newlines but no others. */
- /* Actually, we do limited VT100 parsing, since that seems popular here */
- static void
- plain_dump (FILE * fp, register struct mbuf **bpp)
- {
- struct mbuf *tmp, **tmpp = &tmp;
- int c, esc, nl;
-
- if (bpp == NULLBUFP || *bpp == NULLBUF)
- return;
-
- /* check for lots of non-ASCII, non-VT100 and ascii_dump instead? */
- (void) dup_p (&tmp, *bpp, 0, len_p (*bpp));
- nl = 0;
- while ((c = PULLCHAR (tmpp)) != -1) {
- /*
- * Printable characters are okay, as are \n \t \r \b \f \a \E
- * Nulls and other control characters are verboten, as are meta
- * controls. Meta-printables are accepted, since they may be
- * intended as PC graphics (but don't expect them to dump right
- * from here because I don't decode them. Maybe someday).
- */
- if (c < 8 || (c > 13 && c < 26) || (c > 27 && c < 32) ||
- (c > 126 && c < 174) || c > 223)
- nl = 1;
- }
- if (nl) {
- ascii_dump (fp, bpp);
- return;
- }
- esc = 0;
- nl = 1;
- while ((c = PULLCHAR (bpp)) != -1) {
- if (c == 0x1B)
- esc = !esc;
- else if (esc == 1 && c == '[')
- esc = 2;
- else if (esc == 1)
- esc = 0;
- else if (esc == 2 && c != ';' && !isdigit (c)) {
- /* handle some common cases? */
- esc = 0;
- } else if (esc == 0 && c == '\r') {
- traceprintf (fp, "\n");
- nl = 1;
- }
- /* safe programming: not everyone *always* agrees on isprint */
- else if (esc == 0 && c != '\n' && (isprint (c) || c == '\t')) {
- traceprintf (fp, "%c", c);
- nl = 0;
- }
- }
- if (!nl)
- traceprintf (fp, "\n");
- }
-
- #endif
-
-
- /* Modify or displace interface trace flags */
- int
- dotrace (int argc, char *argv[], void *p OPTIONAL)
- {
- struct iface *ifp;
- struct tracecmd *tp;
-
- if (argc < 2) {
- for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)
- showtrace (ifp);
- return 0;
- }
- if ((ifp = if_lookup (argv[1])) == NULLIF) {
- tprintf (Badinterface, argv[1]);
- return 1;
- }
- #if 0
- if (ifp->port) {
- tprintf ("No trace on this interface - use master.\n");
- return 1;
- }
- #endif
- if (argc == 2) {
- showtrace (ifp);
- return 0;
- }
- /* MODIFY THIS TO HANDLE MULTIPLE OPTIONS */
- if (argc >= 3) {
- for (tp = Tracecmd; tp->name != NULLCHAR; tp++)
- if (strncmp (tp->name, argv[2], strlen (argv[2])) == 0)
- break;
- if (tp->name != NULLCHAR)
- ifp->trace = (int16) ((ifp->trace & (~(unsigned)tp->mask)) | (unsigned)tp->val);
- else
- ifp->trace = (int16) htoi (argv[2]);
- }
- /* Always default to stdout unless trace file is given */
- if (ifp->trsock != -1)
- close_s (ifp->trsock);
- ifp->trsock = -1;
- if (ifp->trfp != NULLFILE && ifp->trfp != stdout)
- (void) fclose (ifp->trfp);
- ifp->trfp = stdout;
- if (ifp->trfile != NULLCHAR)
- free (ifp->trfile);
- ifp->trfile = NULLCHAR;
-
- if (argc >= 4) {
- if (argv[3][0] == '!') {
- /* trace to the current output socket ! */
- ifp->trsock = Curproc->output;
- /* make sure stopping trace doesn't kill connection */
- (void) usesock (ifp->trsock);
- } else if ((ifp->trfp = fopen (argv[3], APPEND_TEXT)) == NULLFILE) {
- tprintf ("Can't write to %s\n", argv[3]);
- ifp->trfp = stdout;
- } else {
- ifp->trfile = strdup (argv[3]);
- if (argc >= 5 && tolower(argv[4][0]) == 'u')
- setbuf (ifp->trfp, NULL);
- }
- }
- showtrace (ifp);
- return 0;
- }
-
-
- /* Display the trace flags for a particular interface */
- static void
- showtrace (register struct iface *ifp)
- {
- if (ifp == NULLIF)
- return;
- tprintf ("%s:", ifp->name);
- #if 0
- if (ifp->port) {
- tprintf (" trace on master interface only.\n");
- return;
- }
- #endif
- if (ifp->trace & (IF_TRACE_IN | IF_TRACE_OUT | IF_TRACE_RAW)) {
- if (ifp->trace & IF_TRACE_IN)
- tprintf (" input");
- if (ifp->trace & IF_TRACE_OUT)
- tprintf (" output");
-
- if (ifp->trace & IF_TRACE_NOBC)
- tprintf (" - no broadcasts");
-
- #ifdef MONITOR
- if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
- tprintf (" (Monitoring)");
- else
- #endif
- if (ifp->trace & IF_TRACE_HEX)
- tprintf (" (Hex/ASCII dump)");
- else if (ifp->trace & IF_TRACE_ASCII)
- tprintf (" (ASCII dump)");
- else
- tprintf (" (headers only)");
-
- if (ifp->trace & IF_TRACE_RAW)
- tprintf (" Raw output");
-
- if (ifp->trfile != NULLCHAR)
- tprintf (" trace file: %s", ifp->trfile);
- else if (ifp->trsock >= SOCKBASE)
- tprintf (" tracing to socket");
- tprintf ("\n");
- } else
- tprintf (" tracing off\n");
- }
-
-
- /* shut down all trace files */
- void
- shuttrace ()
- {
- struct iface *ifp;
-
- for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
- if (ifp->trsock != -1)
- close_s (ifp->trsock);
- if (ifp->trfp != NULLFILE && ifp->trfp != stdout)
- (void) fclose (ifp->trfp);
- if (ifp->trfile != NULLCHAR)
- free (ifp->trfile);
- ifp->trfile = NULLCHAR;
- ifp->trfp = NULLFILE;
- ifp->trsock = -1;
- }
- }
-
- #endif /*TRACE*/
-
-
- #ifdef PPP
- /* Log messages of the form
- * Tue Jan 31 00:00:00 1987 44.64.0.7:1003 open FTP
- */
- #if defined(SCREENSAVER) && defined(UNIX)
- extern int16 intrace;
- #endif
-
- void
- trace_log (struct iface *ifp, const char *fmt,...)
- {
- va_list ap;
- char *cp;
- time_t t;
-
- if (ifp->trfp == NULLFILE)
- return;
-
- (void) time (&t);
- cp = ctime (&t);
- rip (cp);
- traceprintf (ifp->trfp, "%s", cp);
-
- traceprintf (ifp->trfp, " - ");
- va_start (ap, fmt); /*lint !e718 !e746 */
- #if defined(SCREENSAVER) && defined(UNIX)
- intrace = 1;
- #endif
- if (ifp->trfp == stdout)
- (void) usvprintf (tracesock, fmt, ap);
- else
- (void) vfprintf (ifp->trfp, fmt, ap);
- #if defined(SCREENSAVER) && defined(UNIX)
- intrace = 0;
- #endif
- va_end (ap);
- traceprintf (ifp->trfp, "\n");
- }
-
- #endif /* PPP */
-